﻿/*
 * Created by SharpDevelop.
 * User: amb
 * Date: 30/05/2014
 * Time: 15:34
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace JdFormsDll
{
     //<summary>
     //Description of MyClass.
     //</summary>
    public partial class MyForm : Form
    {
        protected ToolTip MyToolTip { get; set; }
        protected bool OnControlBox = false;
        protected const int WM_NCHITTEST = 0x0084;
        protected const int WM_NCLBUTTONDOWN = 0x00A1;
        protected const int WM_SYSCOMMAND = 0x0112;
        protected const int HTCAPTION = 0x0002;
        protected const int SC_MOVE = 0xF010;
        protected const int WM_LBUTTONDBLCLK = 0x00A3;
        protected const int TTDelay = 0x03E8;

        public MyFormDecorator Decorator { get; set; }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_LBUTTONDBLCLK) return;

            if (!this.IsMoveable)
            {
                if (m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MOVE) return;
                if (m.Msg == WM_NCLBUTTONDOWN && m.WParam.ToInt32() == HTCAPTION) return;
            }
            if (m.Msg == WM_NCHITTEST)
            {
                Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
                pos = this.PointToClient(pos);
                if (this.IsMoveable)
                {
                    if (JdHelper.CaptionArea(this.ClientRectangle, this.Padding).Contains(pos))
                    {
                        m.Result = (IntPtr)HTCAPTION;
                        return;
                    }
                }
                if (this.IsResizable)
                {
                    int res = JdHelper.IsOnResizeArea(pos, this.ClientRectangle, this.Padding);
                    if (res > 0)
                    {
                        m.Result = (IntPtr)res;
                        return;
                    }
                }
            }
            base.WndProc(ref m);
        }

        public MyForm()
        {
            base.SetStyle(
                ControlStyles.ResizeRedraw | 
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.SupportsTransparentBackColor, 
                true);
            base.Text = string.Empty;
            base.BackColor = Color.White;
            base.FormBorderStyle = FormBorderStyle.None;
            base.DoubleBuffered = true;
            this.Padding = new Padding(-1);
            JdHelper.MyIcon = this.Icon;
            MyToolTip = new ToolTip();
        }

        protected override void OnLoad(EventArgs e)
        {
            MyToolTip.IsBalloon = false;
            MyToolTip.ToolTipIcon = ToolTipIcon.None;
            MyToolTip.ToolTipTitle = string.Empty;
            MyToolTip.AutoPopDelay = 0x000A;
            MyToolTip.InitialDelay = 0x000A;
            MyToolTip.ReshowDelay = 0x000A;
            MyToolTip.ShowAlways = true;
            base.OnLoad(e);
            this.Invalidate();
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            base.OnInvalidated(e);
            foreach (Control c in this.Controls) c.Invalidate();
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            this.Invalidate();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (this.ControlBox &&
                JdHelper.CloseArea(this.ClientRectangle, this.Padding).Contains(e.Location))
            {
                if (this.ShowTooltip && !this.OnControlBox)
                {
                    int X = JdHelper.CloseArea(this.ClientRectangle, this.Padding).Left;
                    int Y = JdHelper.CloseArea(this.ClientRectangle, this.Padding).Bottom;
                    MyToolTip.Show("Close", this, X, Y, TTDelay);
                    this.OnControlBox = true;
                }
            }
            else if (this.ControlBox && base.MinimizeBox &&
                JdHelper.MinimizeArea(this.ClientRectangle, this.Padding).Contains(e.Location))
            {
                if (this.ShowTooltip && !this.OnControlBox)
                {
                    int X = JdHelper.MinimizeArea(this.ClientRectangle, this.Padding).Left;
                    int Y = JdHelper.MinimizeArea(this.ClientRectangle, this.Padding).Bottom;
                    MyToolTip.Show("Minimize", this, X, Y, TTDelay);
                    this.OnControlBox = true;
                }
            }
            else if (this.ControlBox && base.MaximizeBox && this.IsResizable &&
                JdHelper.ResizeArea(this.ClientRectangle, this.Padding).Contains(e.Location))
            {
                if (this.ShowTooltip && !this.OnControlBox)
                {
                    int X = JdHelper.ResizeArea(this.ClientRectangle, this.Padding).Left;
                    int Y = JdHelper.ResizeArea(this.ClientRectangle, this.Padding).Bottom;
                    string value = (this.WindowState == FormWindowState.Maximized) ? "Normal" : "Maximize";
                    MyToolTip.Show(value, this, X, Y, TTDelay);
                    this.OnControlBox = true;
                }
            }
            else this.OnControlBox = false;

            base.Cursor = (this.OnControlBox) ? Cursors.Hand : Cursors.Default;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (this.ControlBox)
            {
                if (JdHelper.CloseArea(this.ClientRectangle, this.Padding).Contains(e.Location))
                    this.OnFormClosing(new FormClosingEventArgs(CloseReason.UserClosing, false));
                if (base.MaximizeBox &&
                   JdHelper.ResizeArea(this.ClientRectangle, this.Padding).Contains(e.Location) &&
                   this.IsResizable)
                {
                    if (this.WindowState == FormWindowState.Normal)
                        this.WindowState = FormWindowState.Maximized;
                    else this.WindowState = FormWindowState.Normal;
                }
                if (base.MinimizeBox && JdHelper.MinimizeArea(this.ClientRectangle, this.Padding).Contains(e.Location))
                {
                    if (this.WindowState != FormWindowState.Minimized)
                        this.WindowState = FormWindowState.Minimized;
                }
            }
            base.OnMouseDown(e);
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            if (!e.Cancel) base.Dispose();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics gp = e.Graphics;
            gp.SmoothingMode = SmoothingMode.HighQuality;
            gp.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
            gp.CompositingQuality = CompositingQuality.HighQuality;

            gp.Clear(this.BorderColor);

            gp.FillRectangle(new SolidBrush(this.BorderColor), this.ClientRectangle);

            JdHelper.DrawRectBorder(gp,
                JdHelper.ClientArea(this.ClientRectangle, this.Padding),
                this.BackColor, this.BackColorShadow,
                this.ColorsDifferencePercent, this.ShowClientBorder);

            float b = (int)this.CaptionBorderRoundPercent * 1.6f;

            JdHelper.DrawRect(gp,
                JdHelper.TitleBar(this.ClientRectangle, this.Padding),
                this.BackColor, this.BackColorShadow, b,
                this.ShowCaptionBorder, this.ColorsDifferencePercent);

            if (base.ShowIcon)
            {
                Rectangle rIcon = JdHelper.IconArea(this.ClientRectangle, this.Padding);
                rIcon.Inflate(-4, -4);
                if (this.IconImage != null)
                    gp.DrawImage(this.IconImage, rIcon);
                else
                {
                    Bitmap bmp = this.Icon.ToBitmap();
                    gp.DrawImage(bmp, rIcon);
                }
            }

            if (this.ControlBox)
            {
                Color c = this.BackColor.BlackAndWhite();
                JdHelper.DrawClose(gp, this.ClientRectangle, c, this.Padding);
                if (base.MaximizeBox && this.IsResizable) JdHelper.DrawResize(gp, this.ClientRectangle, c, this.Padding, this.WindowState);
                if (base.MinimizeBox) JdHelper.DrawMinimize(gp, this.ClientRectangle, c, this.Padding);
            }

            this.DrawCaptionText(gp);
            ControlPaint.DrawBorder3D(gp, this.ClientRectangle, this.BorderStyle);
        }

        private void DrawCaptionText(Graphics gp)
        {
            using (StringFormat sf = new StringFormat())
            {
                switch (this.TextCaptionAlignment)
                {
                    case ContentAlignment.BottomLeft:
                        sf.LineAlignment = StringAlignment.Far;
                        sf.Alignment = StringAlignment.Near;
                        break;
                    case ContentAlignment.BottomCenter:
                        sf.LineAlignment = StringAlignment.Far;
                        sf.Alignment = StringAlignment.Center;
                        break;
                    case ContentAlignment.BottomRight:
                        sf.LineAlignment = StringAlignment.Far;
                        sf.Alignment = StringAlignment.Far;
                        break;
                    case ContentAlignment.MiddleLeft:
                        sf.LineAlignment = StringAlignment.Center;
                        sf.Alignment = StringAlignment.Near;
                        break;
                    case ContentAlignment.MiddleCenter:
                        sf.LineAlignment = StringAlignment.Center;
                        sf.Alignment = StringAlignment.Center;
                        break;
                    case ContentAlignment.MiddleRight:
                        sf.LineAlignment = StringAlignment.Center;
                        sf.Alignment = StringAlignment.Far;
                        break;
                    case ContentAlignment.TopLeft:
                        sf.LineAlignment = StringAlignment.Near;
                        sf.Alignment = StringAlignment.Near;
                        break;
                    case ContentAlignment.TopCenter:
                        sf.LineAlignment = StringAlignment.Near;
                        sf.Alignment = StringAlignment.Center;
                        break;
                    case ContentAlignment.TopRight:
                        sf.LineAlignment = StringAlignment.Near;
                        sf.Alignment = StringAlignment.Far;
                        break;
                }
                byte shift = (byte)this.TextCaptionShadow;
                using (GraphicsPath gph = new GraphicsPath())
                {
                    gph.AddString(
                        this.Text,
                        this.TextCaptionFont.FontFamily,
                        (int)this.TextCaptionFont.Style,
                        (float)this.TextCaptionFont.Size,
                        JdHelper.CaptionArea(this.ClientRectangle, this.Padding),
                        sf);

                    if (this.TextCaptionColorShadow != this.TextCaptionColor && shift > 0)
                    {
                        using (Pen p = new Pen(this.TextCaptionColorShadow, 2 * shift))
                        {
                            p.Alignment = PenAlignment.Center;
                            p.LineJoin = LineJoin.Round;
                            gp.DrawPath(p, gph);
                        }
                    }

                    gp.FillPath(new SolidBrush(this.TextCaptionColor), gph);

                }
            }
        }
    }
}